/*
 * MIT License
 *
 * Copyright (c) 2023 北京凯特伟业科技有限公司
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */
package com.je.meta.controller.upgrade;

import cn.hutool.core.io.FileUtil;
import com.google.common.base.Strings;
import com.je.common.auth.impl.account.Account;
import com.je.common.base.DynaBean;
import com.je.common.base.document.InternalFileBO;
import com.je.common.base.document.InternalFileUpload;
import com.je.common.base.mvc.AbstractPlatformController;
import com.je.common.base.mvc.BaseMethodArgument;
import com.je.common.base.result.BaseRespResult;
import com.je.common.base.service.CommonService;
import com.je.common.base.service.MetaService;
import com.je.common.base.service.rpc.DocumentInternalRpcService;
import com.je.common.base.upgrade.PackageResult;
import com.je.common.base.util.DateUtils;
import com.je.common.base.util.MessageUtils;
import com.je.common.base.util.SecurityUserHolder;
import com.je.common.base.util.StringUtil;
import com.je.ibatis.extension.conditions.ConditionsWrapper;
import com.je.meta.service.upgrade.UpgradeService;
import com.je.meta.util.enumUtil.UpgradeInstallStateEnum;
import io.swagger.annotations.ApiResponse;
import io.swagger.annotations.ApiResponses;
import org.apache.servicecomb.swagger.invocation.context.ContextUtils;
import org.apache.servicecomb.swagger.invocation.context.InvocationContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.Environment;
import org.springframework.core.io.InputStreamResource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;
import java.io.*;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.util.*;
import java.util.concurrent.CompletableFuture;

@RestController
@RequestMapping(value = "/je/meta/upgrade")
public class UpgradeController extends AbstractPlatformController {

    @Autowired
    private MetaService metaService;
    @Autowired
    private UpgradeService upgradeService;
    @Autowired
    private Environment environment;
    @Autowired
    private DocumentInternalRpcService documentInternalRpcService;
    @Autowired
    private CommonService commonService;

    @RequestMapping(value = {"/getResourceIds"}, method = RequestMethod.POST, produces = "application/json; charset=utf-8")
    public BaseRespResult getResourceIds(BaseMethodArgument param, HttpServletRequest request) {
        String upgradeId = getStringParameter(request, "upgradeId");
        String upgraderesourceType = getStringParameter(request, "type");
        return BaseRespResult.successResult(upgradeService.getResourceIds(upgradeId, upgraderesourceType));
    }

    @Override
    @RequestMapping(value = {"/doSave"}, method = RequestMethod.POST, produces = "application/json; charset=utf-8")
    public BaseRespResult doSave(BaseMethodArgument param, HttpServletRequest request) {
        String oldId = getStringParameter(request, "oldId");
        DynaBean dynaBean = manager.doSave(param, request);
        if (StringUtil.isNotEmpty(oldId)) {
            String result = upgradeService.saveResources(oldId, dynaBean.getStr("JE_META_UPGRADEPACKAGE_ID"));
        }
        return BaseRespResult.successResult(dynaBean.getValues());
    }

    @RequestMapping(value = {"/importDictionaryFromFuncinfo"}, method = RequestMethod.POST, produces = "application/json; charset=utf-8")
    public BaseRespResult importDictionaryFromFuncinfo(HttpServletRequest request) {
        String upgradeId = getStringParameter(request, "upgradeId");
        if (Strings.isNullOrEmpty(upgradeId)) {
            return BaseRespResult.errorResult("请先构建升级包！");
        }

        String result = upgradeService.importDictionaryFromFuncinfo(upgradeId);
        if (StringUtil.isNotEmpty(result)) {
            return BaseRespResult.errorResult(result);
        }
        return BaseRespResult.successResult("导入成功！");
    }

    @RequestMapping(value = {"/importTableByFuncinfo"}, method = RequestMethod.POST, produces = "application/json; charset=utf-8")
    public BaseRespResult importTableByFuncinfo(HttpServletRequest request) {
        String upgradeId = getStringParameter(request, "upgradeId");
        if (Strings.isNullOrEmpty(upgradeId)) {
            return BaseRespResult.errorResult("请先构建升级包！");
        }

        String result = upgradeService.importTableByFuncinfo(upgradeId);
        if (StringUtil.isNotEmpty(result)) {
            return BaseRespResult.errorResult(result);
        }
        return BaseRespResult.successResult("导入成功！");
    }

    @RequestMapping(value = {"/addPackageFuncs"}, method = RequestMethod.POST, produces = "application/json; charset=utf-8")
    public BaseRespResult addPackageFuncs(HttpServletRequest request) {
        String upgradeId = getStringParameter(request, "upgradeId");
        String funcIds = getStringParameter(request, "funcIds");
        if (Strings.isNullOrEmpty(upgradeId)) {
            return BaseRespResult.errorResult("请先构建升级包！");
        }

        if (Strings.isNullOrEmpty(funcIds)) {
            return BaseRespResult.errorResult("请选择要导入的功能！");
        }
        upgradeService.insertPackageFuncs(upgradeId, funcIds);
        return BaseRespResult.successResult("导入成功！");
    }

    @RequestMapping(value = {"/addPackageTables"}, method = RequestMethod.POST, produces = "application/json; charset=utf-8")
    public BaseRespResult addPackageTables(HttpServletRequest request) {
        String upgradeId = getStringParameter(request, "upgradeId");
        String tableIds = getStringParameter(request, "tableIds");
        if (Strings.isNullOrEmpty(upgradeId)) {
            return BaseRespResult.errorResult("请先构建升级包！");
        }

        if (Strings.isNullOrEmpty(tableIds)) {
            return BaseRespResult.errorResult("请选择要导入的表！");
        }

        upgradeService.insertPackageTables(upgradeId, tableIds);
        return BaseRespResult.successResult("导入成功！");
    }

    @RequestMapping(value = {"/addPackageDictionarys"}, method = RequestMethod.POST, produces = "application/json; charset=utf-8")
    public BaseRespResult addPackageDictionarys(HttpServletRequest request) {
        String upgradeId = getStringParameter(request, "upgradeId");
        String dictionaryIds = getStringParameter(request, "dictionaryIds");

        if (Strings.isNullOrEmpty(upgradeId)) {
            return BaseRespResult.errorResult("请先构建升级包！");
        }

        if (Strings.isNullOrEmpty(dictionaryIds)) {
            return BaseRespResult.errorResult("请选择要导入的字典！");
        }
        upgradeService.insertPackageDictionarys(upgradeId, dictionaryIds);
        return BaseRespResult.successResult("导入成功！");
    }

    @RequestMapping(value = {"/addPackageGlobalScripts"}, method = RequestMethod.POST, produces = "application/json; charset=utf-8")
    public BaseRespResult addPackageGlobalScripts(HttpServletRequest request) {
        String upgradeId = getStringParameter(request, "upgradeId");
        String scriptIds = getStringParameter(request, "scriptIds");

        if (Strings.isNullOrEmpty(upgradeId)) {
            return BaseRespResult.errorResult("请先构建升级包！");
        }

        if (Strings.isNullOrEmpty(scriptIds)) {
            return BaseRespResult.errorResult("请选择要导入的全局脚本！");
        }
        upgradeService.insertPackageGlobalScripts(upgradeId, scriptIds);
        return BaseRespResult.successResult("导入成功！");
    }

    @RequestMapping(value = {"/addPackageVariables"}, method = RequestMethod.POST, produces = "application/json; charset=utf-8")
    public BaseRespResult addPackageVariables(HttpServletRequest request) {
        String upgradeId = getStringParameter(request, "upgradeId");
        String variableIds = getStringParameter(request, "variableIds");

        if (Strings.isNullOrEmpty(upgradeId)) {
            return BaseRespResult.errorResult("请先构建升级包！");
        }
        if (Strings.isNullOrEmpty(variableIds)) {
            return BaseRespResult.errorResult("请选择要导入的系统变量！");
        }
        upgradeService.insertPackageSystemVariables(upgradeId, variableIds);
        return BaseRespResult.successResult("导入成功！");
    }

    @RequestMapping(value = {"/addPackageBusinessData"}, method = RequestMethod.POST, produces = "application/json; charset=utf-8")
    public BaseRespResult addPackageBusinessData(HttpServletRequest request) {
        String upgradeId = getStringParameter(request, "upgradeId");
        String tableIds = getStringParameter(request, "tableIds");

        if (Strings.isNullOrEmpty(upgradeId)) {
            return BaseRespResult.errorResult("请先构建升级包！");
        }
        if (Strings.isNullOrEmpty(tableIds)) {
            return BaseRespResult.errorResult("请选择要导入的资源表！");
        }
        upgradeService.insertPackageBusinessData(upgradeId, tableIds);
        return BaseRespResult.successResult("导入成功！");
    }

    /**
     * 打包资源通用（数据源、门户、图标、报表、sql模版）
     *
     * @param request
     * @return
     */
    @RequestMapping(value = {"/addPackageResource"}, method = RequestMethod.POST, produces = "application/json; charset=utf-8")
    public BaseRespResult addPackageDataSource(HttpServletRequest request) {
        String upgradeId = getStringParameter(request, "upgradeId");
        String sourceIds = getStringParameter(request, "sourceIds");
        String type = getStringParameter(request, "type");

        if (Strings.isNullOrEmpty(upgradeId)) {
            return BaseRespResult.errorResult("请先构建升级包！");
        }
        if (Strings.isNullOrEmpty(sourceIds)) {
            return BaseRespResult.errorResult("请选择要导入的资源！");
        }
        upgradeService.insertPackageResource(upgradeId, sourceIds, type);
        return BaseRespResult.successResult("导入成功！");
    }

    /**
     * 打包
     */
    @ApiResponses({
            @ApiResponse(code = 200, response = File.class, message = ""),
    })
    @RequestMapping(value = "/doPackage", method = RequestMethod.GET, consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
    public ResponseEntity<InputStreamResource> doPackage(HttpServletRequest request) throws IOException {
        String upgradeId = getStringParameter(request, "upgradeId");
        if (Strings.isNullOrEmpty(upgradeId)) {
            return ResponseEntity.ok()
                    .header(HttpHeaders.CONTENT_TYPE, "application/json")
                    .body(null);
        }
        DynaBean upgradeBean = metaService.selectOneByPk("JE_META_UPGRADEPACKAGE", upgradeId);
        upgradeBean.setStr("UPGRADEPACKAGE_PACKAGE_TIME", DateUtils.formatDateTime(new Date()));
        //组装业务数据
        List<DynaBean> functionBeanList = new ArrayList<>();
        String platformCode = upgradeBean.getStr("UPGRADEPACKAGE_PLATFORM_CODE");
        if (platformCode.equals("0") || platformCode.equals("1")) {
            functionBeanList = metaService.select("JE_META_UPGRADERESOURCE", ConditionsWrapper.builder()
                    .eq("JE_META_UPGRADEPACKAGE_ID", upgradeBean.getStr("JE_META_UPGRADEPACKAGE_ID"))
                    .orderByAsc("SY_ORDERINDEX"));
        } else {//插件数据
            functionBeanList = upgradeService.buildPluginResources(upgradeBean.getStr("UPGRADEPACKAGE_YWSJ"),
                    upgradeBean.getStr("SY_PRODUCT_ID"),
                    upgradeBean.getStr("SY_PRODUCT_NAME"),
                    upgradeBean.getStr("SY_PRODUCT_CODE"));
        }
        upgradeService.processResourceBeans(upgradeBean, functionBeanList);
        PackageResult packageResult = upgradeService.doPackage(upgradeBean);
        InputStream zipInputStream = upgradeService.buildZip(packageResult, functionBeanList);
        if (zipInputStream == null) {
            return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
                    .header(HttpHeaders.CONTENT_TYPE, "application/json")
                    .body(null);
        }

        String tempDir = environment.getProperty("servicecomb.uploads.directory");
        if (!FileUtil.exist(tempDir)) {
            FileUtil.mkdir(tempDir);
        }

        String fileName = upgradeBean.getStr("UPGRADEPACKAGE_NAME") + ".zip";

        String productName = upgradeBean.getStr("UPGRADEPACKAGE_YWCPMC");
        if (!Strings.isNullOrEmpty(productName)) {
            String version = upgradeBean.getStr("UPGRADEPACKAGE_VERSION");
            fileName = String.format("%s【%s】.zip", upgradeBean.getStr("UPGRADEPACKAGE_NAME"), productName + version);
        }

        File zipFile = FileUtil.writeFromStream(zipInputStream, tempDir + File.separator + fileName);
        InternalFileUpload fileUpload = new InternalFileUpload(fileName, "application/zip", Long.valueOf(zipFile.length()));
        InternalFileBO fileBO = documentInternalRpcService.saveMetaPackageZip(fileUpload, zipFile.getPath(), fileName);
        //修改状态，已打包
        upgradeService.updateState(fileBO, fileName, upgradeId);

        try {
            fileName = URLEncoder.encode(fileName, "UTF-8");
        } catch (UnsupportedEncodingException e) {
            fileName = "未知文件.zip";
        }
        // 用新的文件流创建 InputStreamResource
        InputStreamResource resource = new InputStreamResource(new FileInputStream(zipFile));
        return ResponseEntity.ok()
                .header(HttpHeaders.CONTENT_TYPE, "application/zip")
                .header(HttpHeaders.CONTENT_DISPOSITION, "attachment;filename=" + fileName)
                .body(resource);
    }

    /**
     * 读取文件流
     */
    @RequestMapping(value = "/readPackageFileStream", method = RequestMethod.POST, produces = "application/json; charset=utf-8")
    @ApiResponses({
            @ApiResponse(code = 200, response = File.class, message = ""),
    })
    public ResponseEntity<InputStream> readPackageFileStream() {
        String filePath = ContextUtils.getInvocationContext().getContext("filePath");
        String fileName = ContextUtils.getInvocationContext().getContext("fileName");
        try {
            filePath = URLDecoder.decode(filePath, "UTF-8");
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        try {
            InputStream inputStream = FileUtil.getInputStream(new File(filePath));
            return ResponseEntity.ok()
                    .header(HttpHeaders.CONTENT_LENGTH, String.valueOf(inputStream.available()))
                    .header(HttpHeaders.CONTENT_TYPE, "application/zip")
                    .header(HttpHeaders.CONTENT_DISPOSITION, "attachment;filename=" + fileName)
                    .body(inputStream);
        } catch (Exception e) {
            throw new RuntimeException("文件查找错误");
        }
    }


    /**
     * 创建升级包
     *
     * @return
     */
    @RequestMapping(value = "/uploadPackageWithReturn", method = RequestMethod.POST, produces = "application/json; charset=utf-8", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
    public BaseRespResult uploadPackageWithReturn(HttpServletRequest request) {
        DynaBean dynaBean = (DynaBean) request.getAttribute("dynaBean");
        upgradeService.doSave(dynaBean);
        return BaseRespResult.successResult(dynaBean.getValues(), "创建升级包成功！");
    }

    /**
     * 上传升级包
     *
     * @return
     */
    @RequestMapping(value = "/uploadPackage", method = RequestMethod.POST, produces = "application/json; charset=utf-8", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
    public BaseRespResult uploadPackage(HttpServletRequest request) {
        DynaBean dynaBean = (DynaBean) request.getAttribute("dynaBean");
        upgradeService.doSave(dynaBean);
        return BaseRespResult.successResult("上传成功！");
    }


    /**
     * 安装前校验
     *
     * @return
     */
    @RequestMapping(value = {"/doCheck"}, method = RequestMethod.POST, produces = "application/json; charset=utf-8")
    public BaseRespResult doCheck(HttpServletRequest request) {
        String pkValue = getStringParameter(request, "pkValue");
        String result = upgradeService.doCheck(pkValue);
        if (StringUtil.isNotEmpty(result)) {
            return BaseRespResult.errorResult(result);
        }
        return BaseRespResult.successResult(MessageUtils.getMessage("common.operation.success"));
    }

    /**
     * 执行安装
     *
     * @return
     */
    @RequestMapping(value = {"/doInstall"}, method = RequestMethod.POST, produces = "application/json; charset=utf-8")
    public BaseRespResult doInstall(HttpServletRequest request) {
        Account account = SecurityUserHolder.getCurrentAccount();
        InvocationContext invocationContext = ContextUtils.getInvocationContext();
        CompletableFuture.runAsync(() -> {
            SecurityUserHolder.put(account);
            ContextUtils.setInvocationContext(invocationContext);
            String pkValue = getStringParameter(request, "pkValue");
            DynaBean dynaBean = metaService.selectOneByPk("JE_META_UPGRADEINSTALL", pkValue);
            if (UpgradeInstallStateEnum.INSTALL.getValue().equals(dynaBean.getStr("UPGRADEINSTALL_EXECUTION_STATUS"))) {
                return;
            }
            dynaBean.setStr("UPGRADEINSTALL_EXECUTION_STATUS", "1");
            dynaBean.setStr("UPGRADEINSTALL_YCXX", "");
            metaService.update(dynaBean);
            String fileKey = dynaBean.getStr("UPGRADEINSTALL_FILE_KEY");
            if (Strings.isNullOrEmpty(fileKey)) {
                dynaBean.setStr("UPGRADEINSTALL_EXECUTION_STATUS", "2");
                dynaBean.setStr("UPGRADEINSTALL_YCXX", MessageUtils.getMessage("upgrade.fileKey.isNull"));
                return;
            }

            if (UpgradeInstallStateEnum.INSTALL.getValue().equals(dynaBean.getStr("UPGRADEINSTALL_INSTALL_CODE"))) {
                dynaBean.setStr("UPGRADEINSTALL_EXECUTION_STATUS", "2");
                dynaBean.setStr("UPGRADEINSTALL_YCXX", MessageUtils.getMessage("upgrade.already.install"));
                return;
            }
            upgradeService.doInstall(pkValue, fileKey);
        });
        return BaseRespResult.successResult("后台异步升级中，请关注执行状态！");
    }

    /**
     * 获取执行状态
     *
     * @return
     */
    @RequestMapping(value = {"/upstatus"}, method = RequestMethod.POST, produces = "application/json; charset=utf-8")
    public BaseRespResult upstatus(HttpServletRequest request) {
        String pkValue = getStringParameter(request, "pkValue");
        DynaBean dynaBean = metaService.selectOneByPk("JE_META_UPGRADEINSTALL", pkValue);
        if (dynaBean == null) {
            return BaseRespResult.errorResult("没有找到当前升级记录");
        }
        if ("0".equals(dynaBean.getStr("UPGRADEINSTALL_EXECUTION_STATUS"))) {
            return BaseRespResult.successResult("0", "未执行安装！");
        }
        if ("1".equals(dynaBean.getStr("UPGRADEINSTALL_EXECUTION_STATUS"))) {
            return BaseRespResult.successResult("0", "正在执行！");
        }
        if ("2".equals(dynaBean.getStr("UPGRADEINSTALL_EXECUTION_STATUS"))) {
            return BaseRespResult.successResult("2", Strings.isNullOrEmpty(dynaBean.getStr("UPGRADEINSTALL_YCXX")) ? "安装失败！" : dynaBean.getStr("UPGRADEINSTALL_YCXX"));
        }
        return BaseRespResult.successResult("1", "没有找到当前升级记录");
    }


    @RequestMapping(value = "/remotePackage", method = RequestMethod.POST, produces = "application/json; charset=utf-8")
    public BaseRespResult remotePackage(HttpServletRequest request) {
        generateVersionUpgradePackage(request);
        String code = getStringParameter(request, "code");
        DynaBean dynaBean = metaService.selectOne("JE_META_UPGRADE_PROEUCT", ConditionsWrapper.builder().eq("PROEUCT_CPBM", code));
        //当前版本，还是下个版本
        String version = getStringParameter(request, "version");
        DynaBean dynaBean1 = metaService.selectOne("JE_META_UPGRADE_PRODUCT_VERSION", ConditionsWrapper.builder()
                .eq("JE_META_UPGRADE_PROEUCT_ID", dynaBean.getPkValue())
                .eq("VERSION_BB", version));
        Map<String, String> resultMap = new HashMap<>();
        resultMap.put("VERSION_ZLSJB", dynaBean1.getStr("VERSION_ZLSJB"));
        resultMap.put("VERSION_QLSJB", dynaBean1.getStr("VERSION_QLSJB"));
        return BaseRespResult.successResult(resultMap);
    }


    /**
     * 生成版本升级包
     *
     * @param request
     * @return
     */
    @RequestMapping(value = "/generateVersionUpgradePackage", method = RequestMethod.POST, produces = "application/json; charset=utf-8", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
    public BaseRespResult generateVersionUpgradePackage(HttpServletRequest request) {
        String code = getStringParameter(request, "code");
        //当前版本，还是下个版本
        String version = getStringParameter(request, "version");

        if (Strings.isNullOrEmpty(code)) {
            return BaseRespResult.errorResult("打包失败，请传入产品编码信息！");
        }

        DynaBean dynaBean = metaService.selectOne("JE_META_UPGRADE_PROEUCT", ConditionsWrapper.builder().eq("PROEUCT_CPBM", code));
        String pkValue = dynaBean.getPkValue();
        String productCode = dynaBean.getStr("PROEUCT_CPBM");

        //增量
        String incrementalPackage = upgradeService.generateIncrementalUpgradePackage(dynaBean, productCode, version);
        //全量
        String fullPackage = upgradeService.generateFullUpgradePackage(dynaBean, productCode, version);

        metaService.delete("JE_META_UPGRADE_PRODUCT_VERSION", ConditionsWrapper.builder()
                .eq("JE_META_UPGRADE_PROEUCT_ID", pkValue)
                .eq("VERSION_BB", version)
        );

        DynaBean upgradeProductVersion = new DynaBean("JE_META_UPGRADE_PRODUCT_VERSION", true);
        commonService.buildModelCreateInfo(upgradeProductVersion);
        upgradeProductVersion.setStr("VERSION_BB", version);
        upgradeProductVersion.setStr("VERSION_ZLSJB", incrementalPackage);
        upgradeProductVersion.setStr("VERSION_QLSJB", fullPackage);
        upgradeProductVersion.setStr("JE_META_UPGRADE_PROEUCT_ID", pkValue);
        upgradeProductVersion.setStr("VERSION_CPBM", productCode);
        metaService.insert(upgradeProductVersion);
        return BaseRespResult.successResult("打包成功！");
    }


}
